/*
 * ElevatorProxy.cpp
 *
 */

#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <sstream>
#include "ElevatorProxy.h"

#include "../common/Argv.h"

using namespace std;

ElevatorProxy::ElevatorProxy(int floorAmmount,int elevatorAmmount,float elevatorSpeed,
		 	 	 	 	 	 float maxElevatorCapacity,
		 	 	 	 	 	 std::string floorBaseFileName, std::string keyGenerationPath)
{
	m_floorAmmount = floorAmmount;
	m_ElevatorAmmount = elevatorAmmount;
	m_elevatorSpeed = elevatorSpeed;
	m_maxElevatorCapacity = maxElevatorCapacity;
	m_floorBaseFileName = floorBaseFileName;
	m_keyGenerationPath = keyGenerationPath;
}

ElevatorProxy::~ElevatorProxy()
{
}

void ElevatorProxy::start()
{
    int i;

    pid_t pid;
    m_PidVector.resize(m_ElevatorAmmount);
    m_elevatorDestinationCommunicationVector.resize(m_ElevatorAmmount);

    ElevatorComunicator * destinationComunicator;
    string execFileName = "./elevator";

    for(i=0; i< m_ElevatorAmmount; i++)
    {
    	//Creo la queue del lado del consumidor
    	destinationComunicator = new ElevatorComunicator(m_floorAmmount,(char) i,m_keyGenerationPath);

    	//Creo un nuevo proceso
    	pid = fork();

        if(pid == -1)
            throw new std::exception();

        //Si es el proceso padre
        if(pid != 0)
        {
        	//Registro el canal de comunicacion del hijo y
        	//su pid
        	m_elevatorDestinationCommunicationVector[i] = destinationComunicator;
            m_PidVector[i] = pid;
        }
        else
        {
        	stringstream programArgs;

        	//Llamo al codigo del hijo
            Argv argv;

            programArgs << execFileName << " "<< m_floorAmmount<< " "<<m_elevatorSpeed<< " "
            			<< m_maxElevatorCapacity << " "<<i<< " "<<m_floorBaseFileName
            			<< " "<<m_keyGenerationPath;

//            cout << "ARGS"<< programArgs.str()<<".----" <<endl;
            argv.setSerializedArgs(programArgs.str());

        	if(execv(execFileName.c_str(), argv.getArgv())<0)
			{
				cout << "Error while launching the elevator"<<endl;
				exit(1);
			}
        }
    }

}

void ElevatorProxy::setHallCalls(ElevatorIdentifier elevatorId,
										FloorIdentifierList destinations)
{
	m_elevatorDestinationCommunicationVector[elevatorId]
	                                         ->setHallCalls(destinations);
}

FloorIdentifierList ElevatorProxy::getHallCalls(ElevatorIdentifier elevatorId)
{
	return m_elevatorDestinationCommunicationVector[elevatorId]->getHallCalls();
}

void ElevatorProxy::setAllCalls(ElevatorIdentifier elevatorId,
										FloorIdentifierList destinations)
{
	m_elevatorDestinationCommunicationVector[elevatorId]
	                                         ->setAllCalls(destinations);
}

FloorIdentifierList ElevatorProxy::getAllCalls(ElevatorIdentifier elevatorId)
{
	return m_elevatorDestinationCommunicationVector[elevatorId]->getAllCalls();
}

void ElevatorProxy::setElevatorStatus(ElevatorStatus &status, ElevatorIdentifier elevatorId)
{
	m_elevatorDestinationCommunicationVector[elevatorId]->setElevatorStatus(status);
}

ElevatorStatus ElevatorProxy::getElevatorStatus(ElevatorIdentifier elevatorId)
{
	return m_elevatorDestinationCommunicationVector[elevatorId]->getElevatorStatus();
}

void ElevatorProxy::stop()
{
    int i;
    int processAmmount = m_PidVector.size();

    ElevatorDestinationCommunicatorVector::iterator it;

    for(i=0, it=m_elevatorDestinationCommunicationVector.begin();
    		i < processAmmount && it != m_elevatorDestinationCommunicationVector.end() ;
    		i++, it++)
        kill(m_PidVector[i], SIGINT);

    for(i=0, it=m_elevatorDestinationCommunicationVector.begin();
    		i < processAmmount && it != m_elevatorDestinationCommunicationVector.end() ;
    		i++, it++)
    {
    	waitpid(m_PidVector[i], NULL,0);
    	m_elevatorDestinationCommunicationVector[i]->releaseResources();
    }


    m_elevatorDestinationCommunicationVector.clear();
    m_PidVector.clear();

	m_IsRunning = false;
}

int ElevatorProxy::getElevatorAmmount()
{
	return m_ElevatorAmmount;
}
